;;; Code:

;; -------- awesome-tab --------
(use-package awesome-tab
  :load-path "lazycat-bucket/awesome-tab"
  :hook
  ((after-init) . awesome-tab-mode)
  :config
  (setq awesome-tab-ace-quit-keys '(?\C-g))
  ;; winum users can use `winum-select-window-by-number' directly.
  (defun my-select-window-by-number (win-id)
    "Use `ace-window' to select the window by using window index.
WIN-ID : Window index."
    (let ((wnd (nth (- win-id 1) (aw-window-list))))
      (if wnd
          (aw-switch-to-window wnd)
        (message "No such window."))))
  (defun my-select-window ()
    (interactive)
    (let* ((event last-input-event)
           (key (make-vector 1 event))
           (key-desc (key-description key)))
      (my-select-window-by-number
       (string-to-number (car (nreverse (split-string key-desc "-")))))))
  (defhydra awesome-fast-switch (global-map "C-<tab>" :hint nil)
    "
 ^^^^Fast Move             ^^^^Tab                    ^^Search            ^^Misc
-^^^^--------------------+-^^^^---------------------+-^^----------------+-^^---------------------------
   ^_k_^   prev group    | _C-a_^^     select first | _b_ search buffer | _C-k_   kill buffer
 _h_   _l_  switch tab   | _C-e_^^     select last  | _g_ search group  | _C-S-k_ kill others in group
   ^_j_^   next group    | _C-j_^^     ace jump     | ^^                | ^^
 ^^0 ~ 9^^ select window | _C-h_/_C-l_ move current | ^^                | ^^
-^^^^--------------------+-^^^^---------------------+-^^----------------+-^^---------------------------
"
    ("h" awesome-tab-backward-tab)
    ("j" awesome-tab-forward-group)
    ("k" awesome-tab-backward-group)
    ("l" awesome-tab-forward-tab)
    ("0" my-select-window)
    ("1" my-select-window)
    ("2" my-select-window)
    ("3" my-select-window)
    ("4" my-select-window)
    ("5" my-select-window)
    ("6" my-select-window)
    ("7" my-select-window)
    ("8" my-select-window)
    ("9" my-select-window)
    ("C-a" awesome-tab-select-beg-tab)
    ("C-e" awesome-tab-select-end-tab)
    ("C-j" awesome-tab-ace-jump)
    ("C-h" awesome-tab-move-current-tab-to-left)
    ("C-l" awesome-tab-move-current-tab-to-right)
    ("b" ivy-switch-buffer)
    ("g" awesome-tab-counsel-switch-group)
    ("t" awesome-tab-ace-jump :exit t)
    ("C-k" kill-current-buffer)
    ("C-S-k" awesome-tab-kill-other-buffers-in-current-group)
    ("q" nil "quit"))
  ;; hide tabs
  (defun p1uxtar-awesome-tab-hide-tab (x)
    (let ((name (format "%s" x)))
      (or
       (string-prefix-p "*Ilist*" name)
       (string-prefix-p "*epc" name)
       (string-prefix-p "*helm" name)
       (string-prefix-p "*Compile-Log*" name)
       (string-prefix-p "*lsp" name)
       (and (string-prefix-p "magit" name)
            (not (file-name-extension name)))
       ;; customize hide tabs
       (string-prefix-p "flymake:" name)
       (string-prefix-p "*autoconnect-NOX " name)
       (string-prefix-p "*flycheck" name)
       (string-prefix-p "*NOX " name))))
  (setq awesome-tab-hide-tab-function 'p1uxtar-awesome-tab-hide-tab)
  ;; adjust tab height
  (setq awesome-tab-height 110))

;; -------- centaur-tabs --------
(use-package centaur-tabs
  :config
  (setq centaur-tabs-style "bar"
        centaur-tabs-set-icons t
        centaur-tabs-gray-out-icons 'buffer
        centaur-tabs-set-bar 'under
        x-underline-at-descent-line t
        centaur-tabs-set-close-button nil)
  (centaur-tabs-mode)
  (defun centaur-tabs-buffer-groups ()
    "`centaur-tabs-buffer-groups' control buffers' group rules.
 Group centaur-tabs with mode if buffer is derived from `eshell-mode' `emacs-lisp-mode' `dired-mode' `org-mode' `magit-mode'.
 All buffer name start with * will group to \"Emacs\".
 Other buffer group by `centaur-tabs-get-group-name' with project name."
    (list
     (cond
	  ;; ((not (eq (file-remote-p (buffer-file-name)) nil))
	  ;; "Remote")
	  ((or (string-equal "*" (substring (buffer-name) 0 1))
	       (memq major-mode '(magit-process-mode
				              magit-status-mode
				              magit-diff-mode
				              magit-log-mode
				              magit-file-mode
				              magit-blob-mode
				              magit-blame-mode
				              )))
	   "Emacs")
	  ((derived-mode-p 'prog-mode)
	   "Editing")
	  ((derived-mode-p 'dired-mode)
	   "Dired")
	  ((memq major-mode '(helpful-mode
			              help-mode))
	   "Help")
	  ((memq major-mode '(org-mode
			              org-agenda-clockreport-mode
			              org-src-mode
			              org-agenda-mode
			              org-beamer-mode
			              org-indent-mode
			              org-bullets-mode
			              org-cdlatex-mode
			              org-agenda-log-mode
			              diary-mode))
	   "OrgMode")
	  (t
	   (centaur-tabs-get-group-name (current-buffer))))))
  (defun centaur-tabs-hide-tab (x)
    "Do no to show buffer X in tabs."
    (let ((name (format "%s" x)))
      (or
       ;; Current window is not dedicated window.
       (window-dedicated-p (selected-window))
       ;; Buffer name not match below blacklist.
       (string-prefix-p "*epc" name)
       (string-prefix-p "*helm" name)
       (string-prefix-p "*Helm" name)
       (string-prefix-p "*Compile-Log*" name)
       (string-prefix-p "*lsp" name)
       (string-prefix-p "*company" name)
       (string-prefix-p "*flycheck" name)
       (string-prefix-p "*Flycheck" name)
       (string-prefix-p "*tramp" name)
       (string-prefix-p " *Mini" name)
       (string-prefix-p "*help" name)
       (string-prefix-p "*straight" name)
       (string-prefix-p " *temp" name)
       (string-prefix-p "*Help" name)
       (string-prefix-p "*mybuf" name)
       ;; (string-prefix-p "*autoconnect-NOX " name)
       ;; (string-prefix-p "*NOX " name)
       (string-prefix-p "*One-Key" name)
       ;; Is not magit buffer.
       (and (string-prefix-p "magit" name)
	        (not (file-name-extension name)))
       ))))

;; -------- dashboard --------
(use-package dashboard
  :config
  (dashboard-setup-startup-hook)
  (setq dashboard-banner-logo-title p1uxtar-sayhello)
  ;; (setq dashboard-startup-banner nil)
  (setq dashboard-items '((recents  . 15)
                          ;; (bookmarks . 5)
                          (projects . 5)
                          ;; (agenda . 5)
                          ;; (registers . 5)
                          ))
  (when (display-graphic-p)
    (setq dashboard-set-heading-icons t)
    (setq dashboard-set-file-icons t))
  (setq dashboard-set-init-info t)
  ;; (setq dashboard-init-info "Enjoy counting the parentheses!")
  ;; (setq dashboard-set-footer nil)
  (setq dashboard-footer-messages p1uxtar-sayslogan))

;; -------- mode-line & awesome-tray --------

;; -------- doom-modeline -------- by seagle0128
(use-package doom-modeline
  :custom
  (doom-modeline-minor-modes t)
  (doom-modeline-unicode-fallback t)
  (doom-modeline-mu4e nil)
  :hook (after-init . doom-modeline-mode)
  :init
  ;; Prevent flash of unstyled modeline at startup
  (unless after-init-time
    (setq doom-modeline--default-format mode-line-format)
    (setq-default mode-line-format nil))
  :config
  ;; The limit of the window width, some information won't be displayed.
  (setq doom-modeline-window-width-limit fill-column)
  ;; How to detect the project root.
  (setq doom-modeline-project-detection 'project)
  ;; Whether display icons in the mode-line.
  (setq doom-modeline-icon (display-graphic-p))
  ;; a word count will be added to the selection-info modeline segment.
  (setq doom-modeline-enable-word-count t)
  ;; display the environment version.
  (setq doom-modeline-env-version t)
  ;; display while visiting a symbolink
  (setq find-file-visit-truename t)
  ;; reflect modeline when change branch
  (setq auto-revert-check-vc-info t)
  ;; specify (font family) in modeline
  ;; For example:
  ;; (setq doom-modeline-height 1)
  ;; (set-face-attribute 'mode-line nil :family "Noto Sans" :height 100)
  ;; (set-face-attribute 'mode-line-inactive nil :family "Noto Sans" :height 100)
  ;; or
  ;; (custom-set-faces
  ;;  '(mode-line ((t (:family "Noto Sans" :height 0.9))))
  ;;  '(mode-line-inactive ((t (:family "Noto Sans" :height 0.9)))))
  ;; display cursor positon & size indication.
  (setq column-number-mode t
        line-number-mode t
        size-indication-mode t))

;; -------- mini-modeline with smart-mode-line config --------
(use-package smart-mode-line
  :config
  (sml/setup))
(use-package mini-modeline
  :after smart-mode-line
  :config
  (mini-modeline-mode t))

;; -------- awesome-tray --------
(use-package awesome-tray
  :if window-system
  :load-path "lazycat-bucket/awesome-tray"
  ;; :init
  ;; (setq-default mode-line-format
  ;; 		(remove 'mode-line-buffer-identification mode-line-format))
  :hook
  ((after-init) . awesome-tray-mode)
  :config
  (custom-set-variables
   '(awesome-tray-active-modules '("location" "parent-dir" "git" "mode-name" "date"))))

;; -------- map different functions, distinguish according to `region-active-p' --------
;; emacs-china.org/t/region-active-transient-map/6932/7
(defconst angel-transient-mode-map-alist
  `((mark-active
     ,@(let ((map (make-sparse-keymap)))
         (define-key map "j" #'next-line)
         (define-key map "k" #'previous-line)
         (define-key map "h" 'backward-char)
         (define-key map "l" 'forward-char)
         (define-key map "d" 'p1uxtar-backward-kill-word-or-region)
         (define-key map "o" 'ace-window)
         (define-key map "q" #'keyboard-quit)
         ;; operations
         (define-key map "p" (lambda (b e)
                               (interactive "r") (delete-region b e) (yank)))
         (define-key map "x" #'exchange-point-and-mark)
         (define-key map ";" #'comment-dwim)
         (define-key map "y" #'kill-ring-save)
         (define-key map (kbd "C-y") #'counsel-yank-pop)
         (define-key map "Y" (lambda
                               (b e)
                               (interactive "r")
                               (kill-new (buffer-substring b e))
                               (message "Region saved")))
         ;; mark things
         (define-key map "f" #'er/mark-defun)
         (define-key map "w" #'er/mark-word)
         (define-key map "s" #'er/mark-symbol)
         (define-key map "M-h" #'er/mark-paragraph)
         ;; inner & outer
         ;; (define-key map "C-i" inner-map)
         ;; (define-key map "C-a" outer-map)
         ;; (define-key inner-map "q" #'er/mark-inside-quotes)
         ;; (define-key outer-map "q" #'er/mark-outside-quotes)
         ;; (define-key inner-map "b" #'er/mark-inside-pairs)
         ;; (define-key outer-map "b" #'er/mark-outside-pairs)
         ;; (define-key map "\"" #'er/mark-inside-quotes)
         (define-key map "\"" #'er/mark-outside-quotes)
         (define-key map "(" #'er/mark-inside-pairs)
         (define-key map ")" #'er/mark-outside-pairs)
         ;; expand-region
         ;; (define-key map (kbd "C--") #'er/contract-region)
         ;; (define-key map (kbd "C-=") #'er/expand-region)
         map))))
(add-to-list 'emulation-mode-map-alists
             'angel-transient-mode-map-alist t)

;; -------- powerline --------
(use-package powerline
  :config
  (powerline-default-theme))

;; -------- show the value of the character after point --------
(use-package modeline-char
  :load-path "site-lisp/modeline-char"
  :if (file-exists-p
       (expand-file-name "site-lisp/modeline-char.el"
                         user-emacs-directory))
  :config
  (mlc-char-in-mode-line-mode-global +1))

;; before use package `rotate'
;; switch current windows layout
(defun p1uxtar-switch-windows-layouts ()
  "Switch windows to vertical or horizontal."
  (interactive)
  (when (eq (length (window-list)) 2)
    (cond
     ((eq (window-height) (frame-height))
      (delete-window)
      (con5-split-window-below))
     ((or (eq (window-width) (frame-width))
	      (eq (window-width) (- (frame-width) 1)))
      (delete-window)
      (con5-split-window-right)))))

;; -------- display relative line number --------
(use-package linum-relative
  :defer t
  :config
  (setq linum-relative-backend 'display-line-numbers-mode))

;; -------- display window numbers --------
(use-package winum
  :config
  (defun winum-assign-9-to-calculator-8-to-flycheck-errors ()
    (cond
     ((equal (buffer-name) "*Calculator*") 9)
     ((equal (buffer-name) "*Flycheck errors*") 8)))
  (defun winum-assign-0-to-neotree ()
    (when (string-match-p (buffer-name) ".*\\*NeoTree\\*.*") 10))
  (add-to-list 'winum-assign-functions #'winum-assign-9-to-calculator-8-to-flycheck-errors)
  (add-to-list 'winum-assign-functions #'winum-assign-0-to-neotree)
  (set-face-attribute 'winum-face nil :weight 'bold)
  (setq winum-reverse-frame-list           nil
        winum-auto-assign-0-to-minibuffer  t
        winum-auto-setup-mode-line         t
        winum-format                       "%s"
        winum-mode-line-position           1
        ;; winum-ignored-buffers-regexp       '(" \\*Treemacs-.*")
        winum-ignored-buffers              '(" *which-key*"))
  (winum-mode)
  :bind
  (("C-`" . 'winum-select-window-by-number)
   ("C-²" . 'winum-select-window-by-number)
   ("M-0" . 'winum-select-window-0-or-10)
   ("M-1" . 'winum-select-window-1)
   ("M-2" . 'winum-select-window-2)
   ("M-3" . 'winum-select-window-3)
   ("M-4" . 'winum-select-window-4)
   ("M-5" . 'winum-select-window-5)
   ("M-6" . 'winum-select-window-6)
   ("M-7" . 'winum-select-window-7)
   ("M-8" . 'winum-select-window-8)))
